package org.redr.canvas;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.trolltech.qt.core.QEvent;
import com.trolltech.qt.core.QModelIndex;
import com.trolltech.qt.core.QObject;
import com.trolltech.qt.core.QPoint;
import com.trolltech.qt.core.QPointF;
import com.trolltech.qt.core.QRect;
import com.trolltech.qt.core.QSize;
import com.trolltech.qt.core.Qt;
import com.trolltech.qt.gui.QAbstractItemView;
import com.trolltech.qt.gui.QHBoxLayout;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.gui.QItemDelegate;
import com.trolltech.qt.gui.QItemSelectionModel;
import com.trolltech.qt.gui.QKeyEvent;
import com.trolltech.qt.gui.QLabel;
import com.trolltech.qt.gui.QLineEdit;
import com.trolltech.qt.gui.QListView;
import com.trolltech.qt.gui.QMouseEvent;
import com.trolltech.qt.gui.QPainter;
import com.trolltech.qt.gui.QStandardItem;
import com.trolltech.qt.gui.QStandardItemModel;
import com.trolltech.qt.gui.QStyle;
import com.trolltech.qt.gui.QStyleOptionViewItem;
import com.trolltech.qt.gui.QTextDocument;
import com.trolltech.qt.gui.QWidget;

public class SearchBox extends QLineEdit{

	private QWidget controlArea;
    private QLabel  label;
    private MyQListView listWidget;
	private SearchBoxStandardItemModel model;
	private String enteredText = "";
	private int nrOfSuggestions = 10;
	private int minTextLength = 1;
	private boolean caseSensitive = false;
	private boolean matchAnywhere = true;
	private boolean autoSizeListWidget = true;
	private boolean useRE = true;
	private int maxResults = 10;
	private int descriptionSize = 100;
	private String delimiters = " ";
    
    class MyQListView extends QListView{
    	private QLineEdit parent;
    	public MyQListView(QLineEdit parent){
    		super(parent);
    		this.parent = parent;
    	}
    	
    	@Override
		public void keyPressEvent(QKeyEvent ev){
    		QModelIndex oldIdx = currentIndex();
    		super.keyPressEvent(ev);
    		QModelIndex newIdx = currentIndex();
    		if (oldIdx.row() != newIdx.row()){
    			clicked.emit(newIdx);
    		}
    	}
    	
    	@Override
		public void mousePressEvent(QMouseEvent ev){
    		super.mousePressEvent(ev);
    		activated.emit(indexAt(ev.pos()));
    	}
    	
//    	@Override 
//    	public void eventFilter(QObject object, QEvent event){
//    		
//    	}
    }
    
    class HTMLDelegate extends QItemDelegate{
    	public HTMLDelegate(QLineEdit edit){
    		super(edit);
    	}
    	
    	@Override
		public void paint(QPainter painter, QStyleOptionViewItem option, QModelIndex index){
    		painter.save();
    		if (option.state().isSet(QStyle.StateFlag.State_Selected)){
    			painter.fillRect(option.rect(), option.palette().highlight());
    		}
    		SearchBoxStandardItemModel model = (SearchBoxStandardItemModel) index.model();
    		
    		WidgetRegistry record = (WidgetRegistry) model.listdata.get(index.row());
    		
    		QTextDocument doc = new QTextDocument(this);
    		doc.setHtml(String.format("<strong>%s</strong><br>%s", record.name, record.summary));
    		doc.setTextWidth(option.rect().width()-40);
    		// System.out.println("Adding summary: " + record.summary + " to position " + index.row());
    		// QAbstractTextDocumentLayout_PaintContext ctx = new QAbstractTextDocumentLayout_PaintContext();
    		
    		painter.translate(option.rect().topLeft());
    		QIcon icon = new QIcon(record.icon);
    		drawDecoration(painter, option, new QRect(5,5,32,32), icon.pixmap(new QSize(32,32)));
    		painter.translate(new QPointF(40, 1 + (index.row())));
    		// painter.setClipRect(option.rect().translated(option.rect().topLeft()));
    		doc.drawContents(painter);
    		// QAbstractTextDocumentLayout dl = doc.documentLayout();
    		// dl.draw(painter, ctx);
    		
    		painter.restore();
    		
    	}
    	
    	@Override
		public QSize sizeHint(QStyleOptionViewItem option, QModelIndex index){
    		return new QSize(50,50);
    	}
    	
    	public Qt.ItemFlags flags(QModelIndex index){
    		return new Qt.ItemFlags(Qt.ItemFlag.ItemIsEnabled, Qt.ItemFlag.ItemIsSelectable);
    	}
    }
    
    class SearchBoxStandardItemModel extends QStandardItemModel{
    	public List<Registry> listdata;
    	public SearchBoxStandardItemModel(SearchBox searchBox) {
			// TODO Auto-generated constructor stub
    		super(searchBox);
    		listdata = new ArrayList<Registry>();
		}

		
    }
	
    
	public SearchBox(String l){
		super();
		
		controlArea  = new QWidget();
		label = new QLabel(l);
		controlArea.setLayout(new QHBoxLayout());
		controlArea.layout().addWidget(label);
		
		setMaximumWidth(300);
		setMinimumWidth(300);
		
		setStyleSheet("QLineEdit {border: 2px solid grey; border-radius: 10px; padding: 0 8px;margin-right:60px; selection-background-color: darkgray;}");
		
		listWidget = new MyQListView(this);
		listWidget.setMouseTracking(true);
		listWidget.installEventFilter(this);
		
		listWidget.setWindowFlags(Qt.WindowType.Popup);
		listWidget.setFocusPolicy(Qt.FocusPolicy.NoFocus);
		listWidget.setResizeMode(QListView.ResizeMode.Fixed);
		listWidget.setUniformItemSizes(true);
		
		HTMLDelegate de = new HTMLDelegate(this);
		
		model = new SearchBoxStandardItemModel(this);
		listWidget.setModel(model);
		listWidget.setItemDelegate(de);
		listWidget.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection);
		listWidget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems);
		
		listWidget.activated.connect(this, "doneCompletion()");
		listWidget.indexesMoved.connect(this, "doneCompletion()");
		returnPressed.connect(this, "doneCompletion()");
		textEdited.connect(this, "textEdited()");
		
		setToolTip("Search for widgets and templates by typing directly.");
		// setItems(RedRObjects.registry(), RedRObjects.templates());
	}
	


//	private void setItems(Map<String, WidgetRegistry> registry,
//			Map<String, TemplateRegistry> templates) {
//		
//		
//	}
	
	public void updateSuggestedItems(){
		listWidget.setUpdatesEnabled(false);
		model.clear();
		String[] last = StringUtils.split(this.text(), delimiters);
		if (last.length < 1){ 
			listWidget.hide();
			return;
		}
		List<Registry> matchingValues = new ArrayList<Registry>();
		
		for (WidgetRegistry w : RedRObjects.registry().values()){
			if (containsAll(w.summary, last)){
				matchingValues.add(w);
			} else if (containsAll(w.name, last)){
				matchingValues.add(w);
//			} else if (containsAll(w.details, last)){
//				matchingValues.add(w);
			}
		}
		
		for (TemplateRegistry t : RedRObjects.templates().values()){
			if (containsAll(t.summary, last)){
				matchingValues.add(t);
			}
		}
		
		if (matchingValues.size() < 1){
			listWidget.hide();
			return;
		}
		
		if (matchingValues.size() > maxResults){
			matchingValues = matchingValues.subList(0, maxResults);
		}
		// Pattern p = Pattern.compile(String.format("(%s)", StringUtils.join(last, "|")));
		model.listdata.clear();
		for (Registry r : matchingValues){
			// String name =
			System.out.println("Search matched registry item: " + r.name);
			String theText = String.format("%s (%s)<br>%s", 
					r.name, 
					r.toString(),
					r.details.subSequence(
							0, 
							r.details.length() > descriptionSize ? descriptionSize : r.details.length())
							);
			model.listdata.add(r);
			model.appendRow(new QStandardItem(new QIcon(r.icon), theText));
			
		}
		
		// TODO add the other search bars.
		/*
		 * ### add the websearch 
        theText = 'Web Search <br/>http://www.red-r.org/search/node/%s' % ' '.join(last)
        self.model.listdata.append((theText, {'icon':QIcon(os.path.join(redREnviron.directoryNames['canvasIconsDir'], 'webQuery.png')), 'text':'http://www.red-r.org/search/node/%s' % ' '.join(last)}, 'web'))
        x = QStandardItem(QIcon(os.path.join(redREnviron.directoryNames['canvasIconsDir'], 'webQuery.png')), theText)
        self.model.appendRow(x)
                
        ### add the help search
        theText = 'Local Help Search <br/>%s' % ' '.join(last)
        self.model.listdata.append((theText, {'icon':QIcon(os.path.join(redREnviron.directoryNames['canvasIconsDir'], 'help.png')), 'text':'%s' % ' '.join(last)}, 'help'))
        x = QStandardItem(QIcon(os.path.join(redREnviron.directoryNames['canvasIconsDir'], 'help.png')), theText)
        self.model.appendRow(x)
		 */
		
		QItemSelectionModel selectionModel = listWidget.selectionModel();
		selectionModel.setCurrentIndex(model.index(0, 0), QItemSelectionModel.SelectionFlag.ClearAndSelect);
		
		int height = (matchingValues.size() + 2) * 50;
		int width = this.width();
		
		listWidget.setUpdatesEnabled(true);
		listWidget.resize(width, height);
		listWidget.move(this.mapToGlobal(new QPoint(0, this.height())));
		listWidget.show();
		this.setFocus();
		
		
	}
	
	public void doneCompletion(){
		if (listWidget.isVisible()){
			Registry r = model.listdata.get(listWidget.currentIndex().row());
			this.clear();
			this.listWidget.hide();
			this.setFocus();
			this.searchCallback(r);
		}
		
		
		
	}
	
	public void textEdited(){
		if (this.text().length() == 0){
			this.listWidget.hide();
		} else {
			this.updateSuggestedItems();
		}
	}
	
	public boolean eventFilter(QObject object, QEvent ev){
		// System.out.println("Processing event " + ev.toString() + " on object " + object.toString());
		try{
			if (!object.equals(this) & !object.equals(this.listWidget)) {
				// System.out.println("Clicked the object: " + object.toString());
				return false;
			}
			if (ev.type().equals(QEvent.Type.MouseButtonPress)){
				this.listWidget.hide();
				return true;
			}
		} catch (Exception e){
			return false;
		}
		boolean consumed = false;
		if (ev.type().equals(QEvent.Type.KeyPress)){
			consumed = true;
			List<Integer> lwEventValues = new ArrayList<Integer>(6);
			lwEventValues.add(Qt.Key.Key_Up.value());
			lwEventValues.add(Qt.Key.Key_Down.value());
			lwEventValues.add(Qt.Key.Key_Home.value());
			lwEventValues.add(Qt.Key.Key_End.value());
			lwEventValues.add(Qt.Key.Key_PageUp.value());
			lwEventValues.add(Qt.Key.Key_PageDown.value());
			
			if (((QKeyEvent) ev).key() == Qt.Key.Key_Enter.value() | ((QKeyEvent) ev).key() == Qt.Key.Key_Return.value()){
				this.doneCompletion();
			} else if (((QKeyEvent) ev).key() == Qt.Key.Key_Escape.value()) {
				this.listWidget.hide();
			} else if (lwEventValues.contains(((QKeyEvent) ev).key())){
				this.listWidget.event(ev);
			} else {
				// System.out.println("Pressed the key: " + ((QKeyEvent) ev).text());
				this.event(ev);
			}
		}
		
		return consumed;
	}


	private boolean containsAll(String summary, String[] last) {
		// TODO Auto-generated method stub
		for (String t : last){
			if (!summary.toLowerCase().contains(t)) return false;
			System.out.println(summary + " contains " + t);
		}
		return true;
	}
	
	public void searchCallback(Registry r){
		// if widget
		if (r.type() == 1){
			try {
				RedRObjects.addWidgetByWidgetName(
						((WidgetRegistry) r).forName);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else if (r.type() == 2){ // if template
			
		}
	}


	
	
	
}
